package cn.wolfcode.shop.web.inteceptor;

import cn.wolfcode.shop.domain.User;
import cn.wolfcode.shop.redis.AccessLimitKeyPrefix;
import cn.wolfcode.shop.redis.RedisService;
import cn.wolfcode.shop.redis.key.UserKeyPrefix;
import cn.wolfcode.shop.result.CodeMsg;
import cn.wolfcode.shop.service.ISeckillUserService;
import cn.wolfcode.shop.web.util.AccessLimit;
import cn.wolfcode.shop.web.util.CookieUtil;
import cn.wolfcode.shop.web.util.UserContext;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.invoke.MethodHandle;

/**
 * Created by wolfcode-lanxw
 */
@Component
public class AccessLimitInterceptor extends HandlerInterceptorAdapter {
    @Reference
    private ISeckillUserService seckillUserService;
    @Autowired
    private RedisService redisService;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(handler instanceof HandlerMethod){
            HandlerMethod hm = (HandlerMethod) handler;
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            User user = getUser(request);
            UserContext.set(user);
            if(accessLimit!=null){
                boolean needLogin = accessLimit.needLogin();
                if(needLogin){
                    if(user==null){
                        render(response,CodeMsg.LOGIN_INVAILD);
                        return false;
                    }
                }
                int maxCount = accessLimit.maxCount();
                int seconds = accessLimit.seconds();
                if(maxCount>0 && seconds>0){
                    String uri = request.getRequestURI();
                    AccessLimitKeyPrefix accessLimitKeyPrefix;
                    if(needLogin){
                        accessLimitKeyPrefix = AccessLimitKeyPrefix.withExpire("user:"+user.getId()+":",seconds);
                    }else{
                        String ip = request.getRemoteAddr();
                        accessLimitKeyPrefix = AccessLimitKeyPrefix.withExpire("IP:"+ip+":",seconds);
                    }
                    Integer accessCount = redisService.get(accessLimitKeyPrefix, uri, int.class);
                    if(accessCount==null){
                        redisService.set(accessLimitKeyPrefix,uri,1);
                    }else if(accessCount<maxCount){
                        redisService.incr(accessLimitKeyPrefix,uri);
                    }else{
                        render(response,CodeMsg.ACCESS_LIMIT_ERROR);
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private void render(HttpServletResponse response, CodeMsg codeMsg) throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        String str = JSON.toJSONString(codeMsg);
        response.getWriter().write(str);
    }

    private User getUser(HttpServletRequest request){
        String token = CookieUtil.getCookieValue(request, UserKeyPrefix.TOKEN_NAME);
        if(token!=null){
            User user = seckillUserService.getByToken(token);
            return user;
        }
        return null;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        UserContext.remove();
    }
}
